'use strict';

import queryString from 'query-string';
import FetchBlob from 'rn-fetch-blob';

const loggerTrueColor = 'color: #1ba01b';
const loggerFalseColor = 'color: #f00';

const useFormData = true  // java用formData提交  php为false
/**
 * @默认选项配置
 */
const _settings = {
    url: '',
    method: 'GET',
    headers: {},
    data: null,
    query: null,
    dataType: 'json',
    cache: true,
    useFormData: useFormData,
    accepts: {
        text: 'text/plain',
        html: 'text/html',
        xml: 'application/xml, text/xml',
        json: 'application/json, text/javascript'
    },
    contentType: useFormData ? 'multipart/form-data; charset=UTF-8' : 'application/x-www-form-urlencoded; charset=UTF-8', // PHP后台用这个
};

/**
 * @匹配所有资源类型
 */
const _allType = '*/' + '*';
const _objToString = Object.prototype.toString;
const _fnToString = Function.prototype.toString;

/**
 * [classOf 检测是否属于指定的类型]
 * className 首字母需要大写
 */
function classOf(obj, className) {
    return _objToString.call(obj) === '[object ' + className + ']';
};

/**
 * [isPlainObject 检测对象是否是纯粹的由Object创建的对象]
 * 1. 排除Null和非Object类型的对象
 * 2. 排除宿主对象
 * 3. 排除不是由Object构造函数创建的对象(这也包括了宿主对象)
 */
function isPlainObject(obj) {
    let constructor, proto;
    // IE7/8里的宿主对象是Object类型，而且它们的toString也是Object类型
    if (!obj || !classOf(obj, 'Object') || typeof obj.toString !== 'function') {
        return false;
    }
    if (typeof Object.getPrototypeOf === 'function') {
        proto = Object.getPrototypeOf(obj);
    }
    // Object.prototype 等于 null
    if (proto === null) {
        return true;
    }
    constructor = proto ? proto.constructor : obj.constructor;
    // IE7里的宿主对象的constructor是undefined
    return typeof constructor === 'function' && _fnToString.call(constructor) === _fnToString.call(Object);
};

/**
 * [isArray 检测是否是数组类型]
 */
function isArray(obj) {
    return classOf(obj, 'Array');
};

/**
 * [extend 将一个或多个对象的属性复制到另一个指定的对象上]
 */
function extend(target) {
    let args = [].slice.call(arguments, 1), source;
    while (!!(source = args.shift())) {
        for (let name in source) {
            let copy = source[name];
            let src = target[name];
            if (isPlainObject(copy)) {
                src = isPlainObject(src) ? src : {};
                target[name] = extend(src, copy);
            } else if (isArray(copy)) {
                src = isArray(src) ? src : [];
                target[name] = extend(src, copy);
            } else {
                target[name] = copy;
            }
        }
    }
    return target;
}

function configSettings(settings) {
    // fetch 选项 // 组合默认设置与用户设置
    let options = {}, newSettings = extend({}, _settings, settings);
    newSettings.method = newSettings.method.toUpperCase();
    newSettings.dataType = newSettings.dataType.toLowerCase();
    // GET/HEAD请求不能设置body
    newSettings.hasBody = !/^(?:GET|HEAD)$/.test(newSettings.method);
    // 格式化query为querystring
    newSettings.query = queryString.stringify(newSettings.query || null);
    if (newSettings.uploadFormData && Array.isArray(newSettings.uploadFormData)) {
        let newFormData = [];
        newSettings.uploadFormData.forEach(item => {
            if (item.filename) {
                item.data = FetchBlob.wrap(item.data);
            }
            newFormData.push(item);
        });
        newSettings.uploadFormData = newFormData;
    } else {
        newSettings.uploadFormData = null;
    }
    if (newSettings.data) {
        if (newSettings.useFormData) {
            let formData = new FormData();
            for (const key in newSettings.data) {
                if (newSettings.data.hasOwnProperty(key)) {
                    let value = newSettings.data[key]
                    if (value === undefined || value === null) {
                        value = ''
                    } else if (value.slice) {
                        let newValue = value.slice()
                        if (newValue && (Array.isArray(newValue) || typeof newValue === 'object')) {
                            value = JSON.stringify(newValue)
                        }
                    }
                    formData.append(key, value)
                }
            }
            newSettings.data = formData;
        } else {
            newSettings.data = JSON.stringify(newSettings.data);
        }
    } else {
        newSettings.data = null;
    }
    if (!newSettings.hasBody) {
        // 如果设置了data，将它追加到query中
        if (newSettings.data) {
            newSettings.query += (newSettings.query ? '&' : '') + newSettings.data;
        }
        // 如果设置为不缓存，在query中追加时间戳
        if (newSettings.cache === false) {
            newSettings.query += (newSettings.query ? '&' : '') + '_=' + Date.now();
        }
    } else {
        if (newSettings.data) {
            options.body = newSettings.data;
            newSettings.headers['Content-Type'] = newSettings.contentType;
        } else if (newSettings.uploadFormData) {
            newSettings.headers['Content-Type'] = 'multipart/form-data; charset=UTF-8'
        }
    }
    newSettings.url += (newSettings.query ? (/\?/.test(newSettings.url) ? '&' : '?') + newSettings.query : '');
    // q=0.01 表示权重，数字越小权重越小
    let accept = newSettings.accepts[newSettings.dataType];
    newSettings.headers.Accept = accept ? (accept + ', ' + _allType + '; q=0.01') : _allType;
    options.method = newSettings.method;
    options.headers = newSettings.headers;
    return { newSettings, options };
};

/**
 * [request 包装fetch]
 * @param  settings
 * @return promise
 */
function request(settings) {
    const { newSettings, options } = configSettings(settings);
    return fetch(newSettings.url, options)
        .then((response) => {
            const status = response.status;
            if (response.ok && status >= 200 && status < 300 || status === 304) {
                const dataType = newSettings.dataType || res.headers.get('Content-Type');
                if (settings.type === 'qq_login') {
                    console.log('进来了么');
                    return response.text();
                }
                if (dataType.match(/json/)) {
                    return response.json()
                } else {
                    return response.text()
                }
            } else {
                let error = status + ' ' + (response.statusText || '');
                if (response._bodyText) {
                    error += response._bodyText;
                }
                return Promise.reject(error)
            }
        })
        .then((result) => {
            if (__DEV__) {
                try {
                    console.group('%c请求数据', loggerTrueColor);
                    console.log(`%c请求接口(${options.method})——>>`, loggerTrueColor, newSettings.url);
                    if (options.method === 'GET') {
                        console.log('%c请求参数(QUERY)——>>', loggerTrueColor, queryString.parse(newSettings.query));
                    } else {
                        if (newSettings.useFormData) {
                            console.log('%c请求内容(FORMDATA)——>>', loggerTrueColor, settings.data);
                        } else {
                            console.log('%c请求内容(JSON)——>>', loggerTrueColor, JSON.parse(newSettings.data));
                        }
                    }
                    console.log('%c请求结果——>>', loggerTrueColor, result);
                    console.groupEnd();
                } catch (error) {
                    console.log('%c打印出错——>>', loggerFalseColor, error);
                    console.groupEnd();
                }
            }
            return Promise.resolve(result);
        })
        .catch((error) => {
            if (__DEV__) {
                try {
                    console.group('%c请求数据', loggerFalseColor);
                    console.log(`%c请求接口(${options.method})——>>`, loggerFalseColor, newSettings.url);
                    if (options.method === 'GET') {
                        console.log('%c请求参数(QUERY)——>>', loggerFalseColor, queryString.parse(newSettings.query));
                    } else {
                        if (newSettings.useFormData) {
                            console.log('%c请求内容(FORMDATA)——>>', loggerFalseColor, settings.data);
                        } else {
                            console.log('%c请求内容(JSON)——>>', loggerFalseColor, JSON.parse(newSettings.data));
                        }
                    }
                    console.log('%c请求失败——>>', loggerFalseColor, error);
                    console.groupEnd();
                } catch (error) {
                    console.log('%c打印出错——>>', loggerFalseColor, error);
                    console.groupEnd();
                }
            }
            return Promise.resolve({ code: StatusCode.FAIL_CODE, data: '', msg: error });
        })
};

function requestBlob(settings) {
    const { newSettings, options } = configSettings(settings);
    return FetchBlob.config(newSettings.config)
        .fetch(options.method, newSettings.url, options.headers, newSettings.uploadFormData)
        .uploadProgress((written, total) => {
            console.log('uploaded', written / total);
        })
        .progress((received, total) => {
            console.log('progress', received / total);
        })
        .then((response) => {
            const info = response.info();
            if (info.status === 200) {
                if (info.respType === 'json') {
                    return response.json();
                } else if (info.rnfbEncode === 'path') {
                    return response.path();
                }
            } else {
                let error = status + ' ' + (response.statusText || '');
                if (response._bodyText) {
                    error += response._bodyText;
                }
                return Promise.reject(error);
            }
        })
        .then((result) => {
            if (__DEV__) {
                try {
                    console.group('%c请求数据', loggerTrueColor);
                    console.log(`%c请求接口(${options.method})——>>`, loggerTrueColor, newSettings.url);
                    if (options.method === 'GET') {
                        console.log('%c下载参数(QUERY)——>>', loggerTrueColor, queryString.parse(newSettings.query));
                    } else {
                        if (newSettings.uploadFormData) {
                            console.log('%c上传内容(FORMDATA)——>>', loggerTrueColor, newSettings.uploadFormData);
                        }
                    }
                    console.log('%c请求结果——>>', loggerTrueColor, result);
                    console.groupEnd();
                } catch (error) {
                    console.log('%c打印出错——>>', loggerFalseColor, error);
                    console.groupEnd();
                }
            }
            return Promise.resolve(result);
        })
        .catch((error) => {
            if (__DEV__) {
                try {
                    console.group('%c请求数据', loggerFalseColor);
                    console.log(`%c请求接口(${options.method})——>>`, loggerFalseColor, newSettings.url);
                    if (options.method === 'GET') {
                        console.log('%c下载参数(QUERY)——>>', loggerFalseColor, queryString.parse(newSettings.query));
                    } else {
                        if (newSettings.uploadFormData) {
                            console.log('%c上传内容(FORMDATA)——>>', loggerFalseColor, newSettings.uploadFormData);
                        }
                    }
                    console.log('%c请求失败——>>', loggerFalseColor, error);
                    console.groupEnd();
                } catch (error) {
                    console.log('%c打印出错——>>', loggerFalseColor, error);
                    console.groupEnd();
                }
            }
            return Promise.resolve({ code: StatusCode.FAIL_CODE, data: '', msg: error });
        });
};

/**
 * [get 快捷方法]
 * @param  {[type]} url   [description]
 * @param  {[type]} query [description]
 * @return promise
 */
export function get(url, query, option) {
    const setting = {
        url: url,
        method: 'GET',
        query: { ...query },
        ...option
    };
    return request(setting);
}

/**
 * [post 快捷方法]
 * @param  {[type]} url  [description]
 * @param  {[type]} data [description]
 * @return promise
 */
export function post(url, data, option) {
    const setting = {
        url: url,
        method: 'POST',
        data: { token: global.token, ...data },
        ...option
    };
    return request(setting);
};

/**
 * [upload 快捷方法]
 * @param  {[type]} url  [url]
 * @param  {[type]} formData [{name:'',data:''},{name:'',filename:'',data:''}]
 * @param  {[type]} query [参数]
 * ]
 * @return promise
 */
export function upload(url, formData, option) {
    const setting = {
        url: url,
        method: 'POST',
        uploadFormData: formData,
        config: {},
        ...option
        // uploadProgress: null,
    };
    return requestBlob(setting);
};

/**
 * [upload 快捷方法]
 * @param  {[type]} url  [url]
 * @param  {[type]} formData [{name:'',data:''},{name:'',filename:'',data:''}]
 * @param  {[type]} query [参数]
 * ]
 * @return promise
 */
export function download(url, query, option) {
    const urlArray = url.split('.');
    const setting = {
        url: url,
        method: 'GET',
        query: { ...query },
        config: { fileCache: true, appendExt: urlArray[urlArray.length - 1] },
        ...option
    };
    return requestBlob(setting);
};

/**
 * [upload 快捷方法]
 * @param  {[type]} images  [路径] 必须是数组
 * ]
 * @return promise
 */
export async function uploadQiNiu(images = []) {
    // 需要定义  GET_OSS_TOKEN   QI_NIU_UPLOAD
    const ossData = await post(ServicesApi.GET_OSS_TOKEN, { timestamp: Moment().format('x'), ossType: 'qiniu' });
    // if (ossData.code != StatusCode.SUCCESS_CODE) {
    //     return Promise.resolve({ code: StatusCode.FAIL_CODE, data: [] })
    // }
    let results = [];
    console.log('params', images);
    for (let index = 0; index < images.length; index++) {
        const item = images[index];
        const uuid = Moment().format('x');
        const ext = item.path.split('.').pop();
        let params = [
            { name: 'token', data: ossData.data },
            { name: 'key', data: `qiniu_${uuid}.${ext}` },
            { name: 'file', filename: `qiniu_${uuid}.${ext}`, data: item.path }
        ];
        let uploadRes = await upload(ServicesApi.QI_NIU_UPLOAD, params);
        if (uploadRes) {
            results.push({ key: uploadRes.key })
        }
    }
    if (__DEV__) {
        try {
            console.group('%c开始上传', loggerTrueColor);
            console.log('%c上传结果——>>', loggerTrueColor, results);
            console.groupEnd();
        } catch (error) {
            console.log('%c打印出错——>>', loggerFalseColor, error);
            console.groupEnd();
        }
    }
    if (results.length === 0) {
        return Promise.resolve({ code: StatusCode.FAIL_CODE, data: results });
    }
    return Promise.resolve({ code: StatusCode.SUCCESS_CODE, data: results });
};


